package case23

import (
	"errors"
	"fmt"
	"gorm.io/gorm"
	"reflect"
	"strconv"
)

// OperateUtil GORM操作处理器
type OperateUtil struct {
	db *gorm.DB
}

// NewOperateUtil 创建新的处理器
func NewOperateUtil(db *gorm.DB) *OperateUtil {
	return &OperateUtil{db: db}
}

// 新增
// 参数：
// - tableName: 表名
// - data: 要插入的数据map
// 返回：
// - 插入的记录ID
// - 错误信息
func (h *OperateUtil) AddTable(tableName string, data map[string]interface{}) (int64, error) {
	if len(data) == 0 {
		return 0, errors.New("data cannot be empty")
	}

	result := h.db.Table(tableName).Create(data)
	if result.Error != nil {
		return 0, result.Error
	}

	return result.RowsAffected, nil
}

// 编辑
// 参数：
// - table: 模型实例或表名
// - id: 要更新的记录ID
// - data: 要更新的数据map
// 返回：
// - 影响的行数
// - 错误信息
func (h *OperateUtil) Edit(table interface{}, id uint, data map[string]interface{}) (int64, error) {
	if len(data) == 0 {
		return 0, errors.New("data cannot be empty")
	}

	//// 移除可能存在的ID字段，避免更新主键
	//delete(data, "id")
	//delete(data, "ID")
	//delete(data, "created_at")
	//delete(data, "CreatedAt")

	result := h.db.Model(table).Where("id = ?", id).Updates(data)
	if result.Error != nil {
		return 0, result.Error
	}

	return result.RowsAffected, nil
}

// 编辑
// 参数：
// - table: 模型实例或表名
// - conditions: 更新条件map
// - data: 要更新的数据map
// 返回：
// - 影响的行数
// - 错误信息
func (h *OperateUtil) EditByConditions(table interface{}, conditions map[string]interface{}, data map[string]interface{}) (int64, error) {
	if len(data) == 0 {
		return 0, errors.New("data cannot be empty")
	}

	//// 移除可能存在的ID字段和时间字段
	//delete(data, "id")
	//delete(data, "ID")
	//delete(data, "created_at")
	//delete(data, "CreatedAt")

	query := h.db.Model(table)

	if len(conditions) > 0 {
		//拼接条件
		for key, value := range conditions {
			query = query.Where(key+" = ?", value)
		}
	}

	result := query.Updates(data)
	if result.Error != nil {
		return 0, result.Error
	}

	return result.RowsAffected, nil
}

// 软删除
// 参数：
// - table: 模型实例
// - id: 要删除的记录ID
// 返回：
// - 影响的行数
// - 错误信息
func (h *OperateUtil) SoftDeleteByID(table interface{}, id uint) (int64, error) {
	result := h.db.Delete(table, id)
	if result.Error != nil {
		return 0, result.Error
	}

	return result.RowsAffected, nil
}

// 软删除
// 参数：
// - table: 模型实例
// - conditions: 要删除条件
// 返回：
// - 影响的行数
// - 错误信息
func (h *OperateUtil) SoftDeleteByCondition(table interface{}, conditions map[string]interface{}) (int64, error) {
	if len(conditions) == 0 {
		return 0, errors.New("conditions cannot be empty")
	}

	query := h.db.Model(table)
	for key, value := range conditions {
		query = query.Where(key+" = ?", value)
	}

	result := query.Delete(table)
	if result.Error != nil {
		return 0, result.Error
	}

	return result.RowsAffected, nil
}

// 硬删除
// 参数：
// - table: 模型实例
// - id: 要删除的记录ID
// 返回：
// - 影响的行数
// - 错误信息
func (h *OperateUtil) DeleteByID(table interface{}, id uint) (int64, error) {
	result := h.db.Unscoped().Delete(table, id)
	if result.Error != nil {
		return 0, result.Error
	}

	return result.RowsAffected, nil
}

// ---------
// -----------------------------------------------------------------------------------------

// 新增
// 参数：
// - table: 模型实例或表名（可选，如果model是结构体可以传nil）
// - model: 要插入的数据，可以是结构体、结构体指针、map或slice
// 返回：
// - 插入的记录ID
// - 错误信息
func (h *OperateUtil) Add(model interface{}) error {
	if model == nil {
		return errors.New("model cannot be nil")
	}

	// 检查model是否为空值
	val := reflect.ValueOf(model)
	if val.Kind() == reflect.Ptr {
		if val.IsNil() {
			return errors.New("model pointer cannot be nil")
		}
		val = val.Elem()
	}

	// 检查结构体是否为零值
	if val.Kind() == reflect.Struct && val.IsZero() {
		return errors.New("model cannot be zero value")
	}

	// 执行新增
	result := h.db.Create(model)
	if result.Error != nil {
		return result.Error
	}

	return nil
}

// 新增
// 参数：
// - table: 模型实例或表名（可选，如果model是结构体可以传nil）
// - model: 要插入的数据，可以是map(可非指针)、结构体指针、slice
// 返回：
// - 插入的记录ID
// - 错误信息
func (h *OperateUtil) AddTo(table interface{}, model interface{}) (uint, error) {
	if table == nil {
		return 0, errors.New("table cannot be nil")
	}
	if model == nil {
		return 0, errors.New("model cannot be nil")
	}

	// 检查model是否为空值
	//使用 reflect.ValueOf 获取 model 的反射值
	//如果 model 是指针类型且为 nil，则返回错误
	//如果是指针但非空，则通过 val.Elem() 获取指针指向的实际值
	val := reflect.ValueOf(model)
	if val.Kind() == reflect.Ptr {
		if val.IsNil() {
			return 0, errors.New("model pointer cannot be nil")
		}
		val = val.Elem()
	}

	// 检查model:类型和空值
	var result *gorm.DB
	switch val.Kind() {
	case reflect.Struct:
		if val.IsZero() {
			return 0, errors.New("model-struct cannot be zero value")
		}
		// 获取表名
		tableName, err := h.getTableName(table)
		if err != nil {
			return 0, err
		}
		// 执行新增
		result = h.db.Table(tableName).Create(model)

	case reflect.Map:
		if val.Len() == 0 {
			return 0, errors.New("model-map cannot be zero value")
		}
		// 执行新增
		result = h.db.Model(table).Create(model)

	case reflect.Slice, reflect.Array:
		if val.Len() == 0 {
			return 0, errors.New("model-Slice,Array is null")
		}
		// todo 待续...

	default:
		return 0, errors.New("model-type is null")
	}

	if result.Error != nil {
		return 0, result.Error
	}

	// 获取插入的ID
	return h.getIDFromModel(model)
}

// 批量新增（可配置批量大小）
// 参数：
// - table: 模型实例或表名
// - models: 要插入的数据slice
// - batchSize: 每批插入的大小，0表示使用默认值
// 返回：
// - 错误信息
func (h *OperateUtil) AddToBatch(table interface{}, models interface{}, batchSize int) error {
	if table == nil {
		return errors.New("table cannot be nil")
	}
	if models == nil {
		return errors.New("models cannot be nil")
	}

	// 检查model是否为空值
	//使用 reflect.ValueOf 获取 model 的反射值
	//如果 model 是指针类型且为 nil，则返回错误
	//如果是指针但非空，则通过 val.Elem() 获取指针指向的实际值
	val := reflect.ValueOf(models)
	if val.Kind() == reflect.Ptr {
		if val.IsNil() {
			return errors.New("models pointer cannot be nil")
		}
		val = val.Elem()
	}

	if val.Kind() != reflect.Slice && val.Kind() != reflect.Array {
		return errors.New("models must be slice or array")
	}

	if val.Len() == 0 {
		return errors.New("models slice cannot be empty")
	}

	//// 获取第一个元素
	//firstElem := val.Index(0)
	//elemType := firstElem.Type()
	//actualType := elemType

	var result *gorm.DB
	switch val.Kind() {
	case reflect.Slice, reflect.Array:
		if val.Len() == 0 {
			return errors.New("model-Slice,Array is null")
		}

		if batchSize > 0 {
			// 使用指定批量大小
			result = h.db.Model(table).CreateInBatches(models, batchSize)
		} else {
			// 使用默认批量插入
			result = h.db.Model(table).Create(models)
		}

		//// 获取表名
		//tableName, err := h.getTableName(table)
		//if err != nil {
		//	return err
		//}
		//// 执行新增
		//result = h.db.Table(tableName).CreateInBatches(models, batchSize)
		//
		//// 执行新增
		//result = h.db.Model(table).Create(models)
		// todo 待续...

	default:
		return errors.New("model-type is null")
	}

	if result.Error != nil {
		return result.Error
	}

	return nil
}

//// AddBatch 批量新增泛型版本
//func (h *OperateUtil) AddBatch[T any](models []T) (uint, error) {
//	if len(models) == 0 {
//		return 0, errors.New("models cannot be empty")
//	}
//
//	result := h.db.Create(&models)
//	if result.Error != nil {
//		return 0, result.Error
//	}
//
//	// 返回最后一个元素的ID
//	return h.getIDFromModel(models[len(models)-1])
//}

// getIDFromModel 从模型中提取ID
func (h *OperateUtil) getIDFromModel(model interface{}) (uint, error) {
	if model == nil {
		return 0, errors.New("model is nil")
	}

	val := reflect.ValueOf(model)

	// 处理指针类型
	for val.Kind() == reflect.Ptr {
		if val.IsNil() {
			return 0, errors.New("model pointer is nil")
		}
		val = val.Elem()
	}

	// 根据不同类型处理
	switch val.Kind() {
	case reflect.Struct:
		return h.getIDFromStruct(val)
	case reflect.Map:
		return h.getIDFromMap(val)
	//case reflect.Slice, reflect.Array:
	//	return h.getIDFromSlice(val)
	default:
		// 基础类型直接使用最后插入ID
		return h.getLastInsertID()
	}
}

// getIDFromStruct 从结构体中提取ID
func (h *OperateUtil) getIDFromStruct(val reflect.Value) (uint, error) {
	if !val.IsValid() {
		return 0, errors.New("invalid struct value")
	}

	// 优先查找常见的ID字段名（按优先级排序）
	idFieldNames := []string{"ID", "Id", "id", "FID", "Uid", "UserId"}

	for _, fieldName := range idFieldNames {
		field := val.FieldByName(fieldName)
		if field.IsValid() && field.CanInterface() && !field.IsZero() {
			if id, ok := h.convertToUintSafe(field.Interface()); ok && id > 0 {
				return id, nil
			}
		}
	}

	// 最后回退到数据库最后插入ID
	return h.getLastInsertID()
}

// getIDFromMap 从map中提取ID
func (h *OperateUtil) getIDFromMap(val reflect.Value) (uint, error) {
	if val.Kind() != reflect.Map {
		return 0, errors.New("expected map type")
	}

	if val.Len() == 0 {
		return 0, errors.New("map is empty")
	}

	// 优先查找的key名称（按优先级排序）
	idFieldNames := []string{"id", "ID", "Id", "fid", "uid", "user_id"}

	// 先检查优先级高的key
	for _, key := range idFieldNames {
		keyVal := reflect.ValueOf(key)
		value := val.MapIndex(keyVal)
		if value.IsValid() && !value.IsZero() {
			if id, ok := h.convertToUintSafe(value.Interface()); ok && id > 0 {
				return id, nil
			}
		}
	}

	// 最后回退到数据库最后插入ID
	return h.getLastInsertID()
}

// getLastInsertID 获取最后插入的ID（带重试机制）
func (h *OperateUtil) getLastInsertID() (uint, error) {
	var lastID int64
	var err error

	// 尝试多种SQL写法，提高兼容性
	sqlQueries := []string{
		"SELECT LAST_INSERT_ID()",
		"SELECT last_insert_id()",
		"SELECT @@IDENTITY",
	}

	for _, sql := range sqlQueries {
		err = h.db.Raw(sql).Scan(&lastID).Error
		if err == nil && lastID > 0 {
			return uint(lastID), nil
		}
	}

	if err != nil {
		return 0, fmt.Errorf("failed to get last insert ID: %w", err)
	}

	return 0, errors.New("no valid ID found")
}

// convertToUintSafe 安全地将任意类型转换为uint，返回转换结果和是否成功
func (h *OperateUtil) convertToUintSafe(value interface{}) (uint, bool) {
	if value == nil {
		return 0, false
	}

	switch v := value.(type) {
	case uint:
		return v, true
	case int:
		return uint(v), true
	case int64:
		return uint(v), true
	case int32:
		return uint(v), true
	case uint32:
		return uint(v), true
	case uint64:
		return uint(v), true
	case float32:
		return uint(v), true
	case float64:
		return uint(v), true
	case string:
		// 尝试解析字符串数字
		if intVal, err := strconv.ParseUint(v, 10, 64); err == nil {
			return uint(intVal), true
		}
	}

	return 0, false
}

// GetTableName 根据table参数获取表名
func (h *OperateUtil) getTableName(table interface{}) (string, error) {
	if table == nil {
		return "", errors.New("table cannot be nil")
	}

	// 如果table已经是字符串，直接返回
	if tableName, ok := table.(string); ok {
		return tableName, nil
	}

	// 使用 GORM 的 Statement 解析表结构
	stmt := &gorm.Statement{DB: h.db}
	if err := stmt.Parse(table); err != nil {
		return "", fmt.Errorf("failed to parse table: %w", err)
	}

	if stmt.Schema == nil {
		return "", errors.New("cannot get schema from table")
	}

	return stmt.Schema.Table, nil
}
